package emulator.shell.GUI.debugger;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JToolBar;

import emulator.hardware.HwByte;
import emulator.hardware.HwWord;
import emulator.hardware.nmos6502.Cpu6502;
import emulator.hardware.nmos6502.Flags6502;
import emulator.util.AddressRange;

@SuppressWarnings("serial")
public class CpuRegisterPanel extends JToolBar {
	private Cpu6502 cpu;
    private Font edit_font = new Font("Monospaced", Font.PLAIN, 12);
	private JTextField edit_pc;
	private JTextField edit_accu;
	private JTextField edit_x;
	private JTextField edit_y;
	private JTextField edit_flags;
	private JTextField edit_sp;
	private JTextField edit_ticks;
	private int last_pc = -1;
	private int last_accu = -1;
	private int last_x = -1;
	private int last_y = -1;
	private int last_flags = -1;
	private int last_sp = -1;
	private Color default_color;

	public CpuRegisterPanel(Cpu6502 cpu) {
		super();
		
		this.cpu = cpu;
		initPanel();
		updateValues(cpu.isRunning());
	}

	private void initPanel() {
		edit_pc = createBlock("PC", "$MMMM");
		addSeparator();
		edit_accu = createBlock("AC", "$MM");
		edit_x = createBlock("X", "$MM");
		edit_y = createBlock("Y", "$MM");
		addSeparator();
		edit_flags = createBlock("Flags", "MMMMMMMM");
		addSeparator();
		edit_sp = createBlock("SP", "$MM");
		addSeparator();
		edit_ticks = createBlock("Cycle", "88888888");
		edit_ticks.setFocusable(false);
		addSeparator();
		default_color = edit_pc.getForeground();
	}

	private JTextField createBlock(String title, String init) {
		JLabel label = new JLabel(title);
		JTextField edit = new JTextField(init);
		edit.setFont(edit_font);
		JPanel panel = new JPanel();
		panel.setLayout(new BorderLayout());
		panel.add(label, BorderLayout.NORTH);
		panel.add(edit, BorderLayout.CENTER);
		add(panel);
		return edit;
	}

	public void updateValues(boolean run_state) {
		if (run_state)
		{
			updateText(edit_pc, "????", false, false);
			updateText(edit_accu, "??", false, false);
			updateText(edit_x, "??", false, false);
			updateText(edit_y, "??", false, false);
			updateText(edit_flags, "????????", false, false);
			updateText(edit_sp, "??", false, false);
			updateText(edit_ticks, "???????", false, false);
		}
		else
		{
			int pc = cpu.getPC();
			int accu = (int) cpu.getAccu().getNumber();
			int x = (int) cpu.getX().getNumber();
			int y = (int) cpu.getY().getNumber();
			int flags = (int) cpu.getFlags().getNumber();
			int sp = (int) cpu.getSP().getNumber();
			updateText(edit_pc, "$"+new HwWord(cpu.getPC()).toString(), true, pc != last_pc);
			updateText(edit_accu, "$"+cpu.getAccu().toString(), true, accu != last_accu);
			updateText(edit_x, "$"+cpu.getX().toString(), true, x != last_x);
			updateText(edit_y, "$"+cpu.getY().toString(), true, y != last_y);
			updateText(edit_flags, cpu.getFlags().toFlagString(), true, flags != last_flags);
			updateText(edit_sp, "$"+cpu.getSP().toString(), true, sp != last_sp);
			updateText(edit_ticks, ""+cpu.getTicks(), true, false);
			last_pc = pc;
			last_accu = accu;
			last_x = x;
			last_y = y;
			last_flags = flags;
			last_sp = sp;
		}
	}

	public void transferValuesToCPU()
	{
		if (!cpu.isRunning())
		{
			last_pc = retrieveNumber(edit_pc);
			if (last_pc >= 0)
				cpu.setPC(last_pc);
			else
				last_pc = cpu.getPC(); 
			last_accu = retrieveNumber(edit_accu);
			if (last_accu >= 0)
				cpu.setAccu(new HwByte(last_accu));
			else
				last_accu = (int) cpu.getAccu().getNumber();
			last_x = retrieveNumber(edit_x);
			if (last_x >= 0)
				cpu.setX(new HwByte(last_x));
			else
				last_x = (int) cpu.getX().getNumber();
			last_y = retrieveNumber(edit_y);
			if (last_y >= 0)
				cpu.setY(new HwByte(last_y));
			else
				last_y = (int) cpu.getY().getNumber();
			Flags6502 flags = new Flags6502();
			flags.fromFlagString(edit_flags.getText());
			last_flags = (int) flags.getNumber();
			cpu.setFlags(flags);
			last_sp = retrieveNumber(edit_sp);
			if (last_sp >= 0)
				cpu.setSP(new HwByte(last_sp));
			else
				last_sp = (int) cpu.getSP().getNumber();
		}
	}
	
	private void updateText(JTextField edit, String text, boolean is_editable, boolean has_changed) {
		edit.setText(text);
		edit.setEditable(is_editable);
		edit.setForeground(has_changed ? Color.red : default_color);
	}
	
	private int retrieveNumber(JTextField edit) {
		String number_text = edit.getText();
		int number = -1;
		try { number = AddressRange.addressFromString(number_text); }
		catch (NumberFormatException e)	{ }
		return number;
	}
}
